#include "expression.h"

#include <QStack>
#include <QRegExp>
#include "binaryoperator.h"
#include <QDebug>

namespace AltMath {

     bool isNumber(const QString& token){
          static QRegExp numberRegexp("\\d+\\.*\\d*");
          return numberRegexp.exactMatch(token);
     }

     bool isOperator(const QString& token){
          static QRegExp opRegexp("[-\\+\\*/\\^%]");
          return opRegexp.exactMatch(token);
     }

     BinaryOperator::Operation operation(const QString& token){
          if(token == "+"){
               return BinaryOperator::Addition;
          } else if(token == "-"){
               return BinaryOperator::Subtraction;
          } else if(token == "*"){
               return BinaryOperator::Multiplication;
          } else if(token == "/"){
               return BinaryOperator::Division;
          } else if(token == "^"){
               return BinaryOperator::Exponentiation;
          } else if(token == "%"){
               return BinaryOperator::Modulo;
          }
          return BinaryOperator::Addition;
     }

     bool Expression::infixToPostfix(QString expr, QString& result, QString& error){
          expr.remove(QRegExp("\\s+"));
          QRegExp regexp("(\\d+\\.*\\d*|[-\\+\\*/\\^%]|[\\(\\)])");
          int pos = 0;
          QStack<QString> opStack;
          while((pos = regexp.indexIn(expr, pos)) != -1){
               QString token = regexp.cap(1);
               if(isNumber(token)){
                    result += token += " ";
               } else if(isOperator(token)){
                    BinaryOperator::Operation op1 = operation(token);
                    while((!opStack.isEmpty()) && (isOperator(opStack.top()))){\
                         BinaryOperator::Operation op2 = operation(opStack.top());
                         if(BinaryOperator::precedence(op1) <= BinaryOperator::precedence(op2)){
                              result += opStack.pop() += " ";
                         } else {
                              break;
                         }
                    }
                    opStack.push(token);
               } else if(token == "("){
                    opStack.push(token);
               } else if(token == ")"){
                    bool leftParenFound = false;
                    while(!opStack.isEmpty()){
                         QString op = opStack.pop();
                         if(op == "("){
                              leftParenFound = true;
                              break;
                         } else {
                              result += op += " ";
                         }
                    }
                    if(!leftParenFound){
                         error = "Mismatched parentheses.";
                         return false;
                    }
               }
               pos += regexp.matchedLength();
          }
          while(!opStack.isEmpty()){
               if(opStack.top() == "("){
                    error = "Mismatched parentheses.";
                    result = "";
                    return false;
               }
               result += opStack.pop() += " ";
          }
          return true;
     }
}
